import logging
from typing import Any

from pydantic.fields import FieldInfo
from pydantic_settings import BaseSettings, PydanticBaseSettingsSource, SettingsConfigDict
from configs.babel import BabelConfig
from configs.deploy import DeploymentConfig
from configs.extra import ExtraServiceConfig
from configs.feature import FeatureConfig
from configs.middleware import MiddlewareConfig
from configs.observability import ObservabilityConfig
from configs.packaging import PackagingInfo
from configs.remote_settings_sources import RemoteSettingsSourceConfig
from configs.remote_settings_sources.apollo import ApolloSettingsSource
from configs.remote_settings_sources.base import RemoteSettingsSource
from configs.remote_settings_sources.enums import RemoteSettingsSourceName
from configs.remote_settings_sources.nacos import NacosSettingsSource
from configs.robot import RobotServerConfig
from configs.sms import SMSConfig
logger = logging.getLogger(__name__)


class RemoteSettingsSourceFactory(PydanticBaseSettingsSource):
    def __init__(self, settings_cls: type[BaseSettings]):
        super().__init__(settings_cls)

    def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str, bool]:
        raise NotImplementedError

    def __call__(self) -> dict[str, Any]:
        current_state = self.current_state
        remote_source_name = current_state.get("REMOTE_SETTINGS_SOURCE_NAME")
        if not remote_source_name:
            return {}

        remote_source: RemoteSettingsSource | None = None
        match remote_source_name:
            case RemoteSettingsSourceName.APOLLO:
                remote_source = ApolloSettingsSource(current_state)
            case RemoteSettingsSourceName.NACOS:
                remote_source = NacosSettingsSource(current_state)
            case _:
                logger.warning(f"Unsupported remote source: {remote_source_name}")
                return {}

        d: dict[str, Any] = {}

        for field_name, field in self.settings_cls.model_fields.items():
            field_value, field_key, value_is_complex = remote_source.get_field_value(field, field_name)
            field_value = remote_source.prepare_field_value(field_name, field, field_value, value_is_complex)
            if field_value is not None:
                d[field_key] = field_value

        return d


class AppConfig(
    # Packaging info
    PackagingInfo,
    # Deployment configs
    DeploymentConfig,
    # Middleware configs
    MiddlewareConfig,
    # Observability configs
    ObservabilityConfig,
    # Feature configs
    FeatureConfig,
    # Extra service configs
    ExtraServiceConfig,
    # Remote source configs
    RemoteSettingsSourceConfig,
    # Mouse service configs
    SMSConfig,
    # Babel configs
    BabelConfig,
    # RobotServer configs
    RobotServerConfig,
):
    model_config = SettingsConfigDict(
        # read from dotenv format config file
        env_file=".env",
        env_file_encoding="utf-8",
        # ignore extra attributes
        extra="ignore",
    )

    # Before adding any config,
    # please consider to arrange it in the proper config group of existed or added
    # for better readability and maintainability.
    # Thanks for your concentration and consideration.

    @classmethod
    def settings_customise_sources(
        cls,
        settings_cls: type[BaseSettings],
        init_settings: PydanticBaseSettingsSource,
        env_settings: PydanticBaseSettingsSource,
        dotenv_settings: PydanticBaseSettingsSource,
        file_secret_settings: PydanticBaseSettingsSource,
    ) -> tuple[PydanticBaseSettingsSource, ...]:
        return (
            init_settings,
            env_settings,
            RemoteSettingsSourceFactory(settings_cls),
            dotenv_settings,
            file_secret_settings,
        )
